﻿using System;
using System.IO;
using System.Collections.Generic;
using System.Text;
using System.Net;
using System.Web;
using System.Web.Mvc;
using BSU.GraduateWork.BL;
using BSU.GraduateWork.Data.Model;
using BSU.GraduateWork.Data.Repositories;
using BSU.GraduateWork.Web.Models;
using BSU.Math.Geometry;

using System.Linq;


namespace BSU.GraduateWork.Web.Controllers
{
    [HandleError]
    public class SolutionController : Controller
    {
        #region Step1

        [AcceptVerbs(HttpVerbs.Get)]
        public ActionResult Step1()
        {
            return View();
        }

        #endregion

        #region Step2

        [AcceptVerbs(HttpVerbs.Get)]
        public ActionResult Step2()
        {
            return View();
        }

        [AcceptVerbs(HttpVerbs.Post)]
        public ActionResult Step2(FormCollection form)
        {
            var dim  = form["dim"] == "2" ? "2D" : "3D";
            return RedirectToAction(String.Format("{0}/Step3", dim), new { type = Request.Params["type"] });
        }

        #endregion

        #region Step3

        [AcceptVerbs(HttpVerbs.Get)]
        public ActionResult Step3(string dimension)
        {
            return View();
        }

        #endregion

        #region Step4

        [AcceptVerbs(HttpVerbs.Get)]
        public ActionResult Step4(string dimension)
        {
            switch (dimension.ToUpperInvariant())
            {
                case "3D":
                    {
                        var problem = new Problem3D
                        {
                            InputParameters = new InputParameters3D
                            {
                                N = 100,
                                X1 = 0,
                                X2 = 1,
                                Y1 = 0,
                                Y2 = 1,
                                G = 0,
                                Epsilon = 0.0001,
                                H = 0.3,
                                Alpha = 0.00001
                            }
                        };

                        return View(new SolutionModel(problem));
                    }; break;
                case "2D":
                    {
                        var problem = new Problem2D
                        {
                            InputParameters = new InputParameters2D
                            {
                                N = 100,
                                X1 = 0,
                                X2 = 1,
                                Y1 = 0,
                                Y2 = 1,
                                G = 0,
                                Epsilon = 0.00001,
                                H = 0.23,
                                Alpha = 0.00001
                            }
                        };

                        return View("2D/Step4", new Solution2DModel(problem));
                    }; break;
            }
            return View();
        }

        [AcceptVerbs(HttpVerbs.Post)]
        public ActionResult Step4([Bind(Exclude = "Id")] Solution2DModel model, string dimension)
        {
            switch (dimension.ToUpperInvariant())
            {
                case "2D":{
                    GridFreeMethodFor2D method = null;
                    if (Request.Params["how"] == "0")
                    {
                        method = new GridFreeMethodFor2D(model.Problem, false);
                        method.Problem.ExactSolution.U = ReadPointsFromFile();
                        method.Problem.Solution.U = method.Problem.ExactSolution.U.Select(x => new Point3D(x.X, x.Y, 0, x.IsBoundary)).ToList();
                        method.Problem.InputParameters.N = method.Problem.Solution.U.Count;
                    }
                    else
                    {
                        method = new GridFreeMethodFor2D(model.Problem, true);
                    }

                    method.Problem.Type = Request.Params["type"] == "3" ? ProblemType.TypeThree : ProblemType.Simple;

                    method.Solve();
                    model.Problem = method.Problem;
                    model.State = Solution2DModel.ModelState.Solved;

                    var repository = new Problem2DRepository();
                    var problem = repository.Save(model.Problem);

                    return RedirectToAction("2D/Display", new { id = problem.Id });
                }; break;
            }

            return View();
        }

        #endregion

        [AcceptVerbs(HttpVerbs.Get)]
        public ActionResult Display(string dimension, int id)
        {
            switch (dimension.ToUpperInvariant())
            {
                case "3D":
                    {
                        var repository = new ProblemRepository();
                        var problem = repository.Get(id);

                        return View("3D/Display", new SolutionModel(problem, SolutionModel.ModelState.Solved));
                    }; break;
                case "2D":
                    {
                        var repository = new Problem2DRepository();
                        var problem = repository.Get(id);
                        return View("2D/Display", new Solution2DModel(problem, Solution2DModel.ModelState.Solved));
                    }; break;
            }
            return View();
        }

        //[AcceptVerbs(HttpVerbs.Get)]
        //public ActionResult Step3()
        //{
        //    var problem = new Problem3D
        //    {
        //        InputParameters = new InputParameters3D
        //        {
        //            N = 1000,
        //            X1 = 0,
        //            X2 = 1,
        //            Y1 = 0,
        //            Y2 = 1,
        //            Z1 = 0,
        //            Z2 = 1,
        //            G = 0,
        //            Epsilon = 0.0001,
        //            H = 0.3,
        //            Alpha = 0.00001
        //        }
        //    };

        //    return View(new SolutionModel(problem));
        //}

        //[AcceptVerbs(HttpVerbs.Post)]
        //public ActionResult Step3([Bind(Exclude = "Id")] SolutionModel model)
        //{
        //    var method = new GridFreeMethodFor3D(model.Problem);
        //    method.AutoGeneratePoints = true;
        //    method.Solve();
        //    model.Problem = method.Problem;
        //    model.State = SolutionModel.ModelState.Solved;

        //    var repository = new ProblemRepository();
        //    var problem = repository.Save(model.Problem);

        //    return RedirectToAction("Display", new { id = problem.Id });
        //}

        [AcceptVerbs(HttpVerbs.Get)]
        public ActionResult Index(string dimension, int id)
        {
            switch (dimension.ToUpperInvariant())
            {
                case "2D":
                    {
                        var problem = new Problem2D
            {
                InputParameters = new InputParameters2D
                {
                    N = 100,
                    X1 = 0,
                    X2 = 1,
                    Y1 = 0,
                    Y2 = 1,
                    G = 0,
                    Epsilon = 0.0001,
                    H = 0.3,
                    Alpha = 0.00001
                }
            };

                        return View("Index2D", new Solution2DModel(problem));
                    }; break;

                case "3D":
                    {
                        var problem = new Problem3D
                        {
                            InputParameters = new InputParameters3D
                            {
                                N = 1000,
                                X1 = 0,
                                X2 = 1,
                                Y1 = 0,
                                Y2 = 1,
                                Z1 = 0,
                                Z2 = 1,
                                G = 0,
                                Epsilon = 0.0001,
                                H = 0.3,
                                Alpha = 0.00001
                            }
                        };

                        return View("Index3D", new SolutionModel(problem));
                    }; break;
            }

            return View();
        }

        //[AcceptVerbs(HttpVerbs.Get)]
        //public ActionResult Step3()
        //{
        //    var problem = new Problem2D
        //    {
        //        InputParameters = new InputParameters2D
        //        {
        //            N = 100,
        //            X1 = 0,
        //            X2 = 1,
        //            Y1 = 0,
        //            Y2 = 1,
        //            G = 0,
        //            Epsilon = 0.0001,
        //            H = 0.3,
        //            Alpha = 0.00001
        //        }
        //    };

        //    return View(new Solution2DModel(problem));
        //}



        private List<Point3D> ReadPointsFromFile()
        {
            var points = new List<Point3D>();

            Stream stream;
            HttpPostedFileBase file = Request.Files["Solution"];
            stream = file.InputStream;

            using (var sr = new StreamReader(stream))
            {
                var line = sr.ReadLine();
                var xCoordinates = line.Split(new char[] { '\t' }, StringSplitOptions.RemoveEmptyEntries).Select(x => Double.Parse(x)).ToList();

                line = sr.ReadLine();
                var yCoordinates = line.Split(new char[] { '\t' }, StringSplitOptions.RemoveEmptyEntries).Select(x => Double.Parse(x)).ToList();

                line = sr.ReadLine();
                var uCoordinates = line.Split(new char[] { '\t' }, StringSplitOptions.RemoveEmptyEntries).Select(x => Double.Parse(x)).ToList();

                for (int i = 0; i < xCoordinates.Count; i++)
                {
                    points.Add(new Point3D(xCoordinates[i], yCoordinates[i], uCoordinates[i],
                                           xCoordinates[i] == 0 || yCoordinates[i] == 0 ||
                                           xCoordinates[i] == 1 || yCoordinates[i] == 1));
                }
            }

            return points;
        }
    }
}